﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

using Metriks.Parsiranje;
using QuickGraph;
using GraphSharp;
using GraphSharp.Controls;
using Metriks.NezavisniPutevi;
using System.ComponentModel;

namespace Metriks.Prezentacija.McCabe
{
    /// <summary>
    /// Interaction logic for GraphDisplay.xaml
    /// </summary>
    public partial class GraphDisplay : Window, INotifyPropertyChanged
    {
        private IBidirectionalGraph<object, IEdge<object>> _graphToVisualize;


        public IBidirectionalGraph<object, IEdge<object>> GraphToVisualize
        {
            get { return _graphToVisualize; }
            set
            {
                this._graphToVisualize = value;
                this.RaisePropChanged("GraphToVisualize");
            }
        }

        #region zadaća3

        public GraphDisplay(Cvor pocetni)
        {
            CreateGraphToVisualize(pocetni);
            InitializeComponent();
            cb_nezavisniputevi.IsEnabled = false;
        }

        private void CreateGraphToVisualize(Cvor c)
        {
            var g = new BidirectionalGraph<object, IEdge<object>>();
            List<Cvor> vertices = new List<Cvor>();
            povadiCvoroveIzStabla(c, vertices);
            očistiDuplikate(vertices);
            //dodajemo čvorove
            foreach (Cvor cvor in vertices)
            {
                g.AddVertex(cvor);
            }
            //dodajemo linkove
            foreach (Cvor cvor in vertices)
            {
                foreach (Cvor target in cvor.Cvorovi)
                {
                    g.AddEdge(new Edge<object>(cvor, target));
                }
            }
            _graphToVisualize = g;
        }

        private void očistiDuplikate(List<Cvor> popuniMe)
        {
            for (int i = 0; i < popuniMe.Count; i++)
            {
                // ako je flow kojeg slijedi flow..
                if (popuniMe[i].Tip == "Flow" && popuniMe[i].Cvorovi.Count == 1 && popuniMe[i].Cvorovi[0].Tip == "Flow")
                {
                    // i ako ima samo jednog roditelja
                    int brPrethodnika = 0;
                    int tempind = -1;
                    int ind = -1;
                    Cvor prethodnik = null;
                    foreach (Cvor c in popuniMe)
                    {
                        tempind = c.Cvorovi.IndexOf(popuniMe[i]);
                        if (tempind != -1)
                        {
                            ind = tempind;
                            prethodnik = c;
                            brPrethodnika++;
                        }
                    }

                    if (brPrethodnika == 1)
                    {
                        prethodnik.Cvorovi[ind] = popuniMe[i].Cvorovi[0];
                        popuniMe.RemoveAt(i);
                        i--;
                    }
                }
            }
        }

        private void povadiCvoroveIzStabla(Cvor c, List<Cvor> popuniMe)
        {
            if (popuniMe.Contains(c))
                return;
            popuniMe.Add(c);
            foreach (Cvor dijete in c.Cvorovi)
                povadiCvoroveIzStabla(dijete, popuniMe);
        }


        #endregion

        #region zadaća4

        public void RaisePropChanged(string name)
        {
            var eh = this.PropertyChanged;
            if (eh != null)
            {
                eh(this, new PropertyChangedEventArgs(name));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public GraphDisplay(Cvor pocetni, int mccabekompleksnost)
        {
            grane = new List<EdgeNaPutu>();
            CreateGraphToVisualizePutanje(pocetni);

            InitializeComponent();

            this.Title = "Prikaz nezavisnih puteva";
            cb_putevi.ItemsSource = putanje;
            cb_nezavisniputevi.ItemsSource = putanjeNeovisne;

            ciklomatskakompleksnost = mccabekompleksnost;

            SwitchingUnderWay = false;
        }

        private int ciklomatskakompleksnost;
        private List<Putanja> putanje;
        private List<Putanja> putanjeNeovisne;
        private List<EdgeNaPutu> grane;
        private List<Cvor> vertices;

        private void CreateGraphToVisualizePutanje(Cvor c)
        {
            var g = new BidirectionalGraph<object, IEdge<object>>();

            vertices = new List<Cvor>();
            povadiCvoroveIzStabla(c, vertices);
            očistiDuplikate(vertices);
            
            // debugging point 1
            putanje = NPFactory.pronađiSvePuteve(vertices[0]);

            // debugging point 2
            putanjeNeovisne = NPFactory.pronađiNeovisnePuteve(putanje);

            //dodajemo čvorove
            foreach (Cvor cvor in vertices)
                g.AddVertex(cvor);
            //dodajemo linkove
            foreach (Cvor cvor in vertices)
            {
                foreach (Cvor target in cvor.Cvorovi)
                {
                    EdgeNaPutu grana = new EdgeNaPutu(cvor, target) { EdgeColor = Colors.Black };
                    g.AddEdge(grana);
                    grane.Add(grana);
                }
            }

            GraphToVisualize = g;
        }

        private void cb_nezavisniputevi_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (cb_nezavisniputevi.SelectedIndex == -1 || SwitchingUnderWay)
                return;
            else
            {
                SwitchingUnderWay = true;
                cb_putevi.SelectedIndex = -1;
                SwitchingUnderWay = false;

                Putanja odabrana = putanjeNeovisne[cb_nezavisniputevi.SelectedIndex];
                odabrana.buildLinks();
                var g = new BidirectionalGraph<object, IEdge<object>>();
//                 MessageBox.Show(odabrana.ToString());
//                 MessageBox.Show(odabrana.EdgesToString());
                //dodajemo čvorove
                foreach (Cvor cvor in vertices)
                    g.AddVertex(cvor);
                //dodajemo linkove
                foreach (Cvor cvor in vertices)
                {
                    foreach (Cvor target in cvor.Cvorovi)
                    {
                        Putanja.Link edge = new Putanja.Link(cvor, target);
                        /*MessageBox.Show(edge.ToString()+ " je sadržan u putanji: "+odabrana.Contains(edge));*/
                        Color boja = (odabrana.Contains(edge)) ? Colors.Red : Colors.Black;
                        EdgeNaPutu grana = new EdgeNaPutu(cvor, target) { EdgeColor = boja };
                        g.AddEdge(grana);
                        grane.Add(grana);
                    }
                }

                GraphToVisualize = g;
            }
        }

        private bool SwitchingUnderWay { get; set; }

        private void cb_putevi_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (cb_putevi.SelectedIndex == -1 || SwitchingUnderWay)
                return;
            else
            {
                SwitchingUnderWay = true;
                cb_nezavisniputevi.SelectedIndex = -1;
                SwitchingUnderWay = false;

                Putanja odabrana = putanje[cb_putevi.SelectedIndex];
                odabrana.buildLinks();
                var g = new BidirectionalGraph<object, IEdge<object>>();
                //                 MessageBox.Show(odabrana.ToString());
                //                 MessageBox.Show(odabrana.EdgesToString());
                //dodajemo čvorove
                foreach (Cvor cvor in vertices)
                    g.AddVertex(cvor);
                //dodajemo linkove
                foreach (Cvor cvor in vertices)
                {
                    foreach (Cvor target in cvor.Cvorovi)
                    {
                        Putanja.Link edge = new Putanja.Link(cvor, target);
                        /*MessageBox.Show(edge.ToString()+ " je sadržan u putanji: "+odabrana.Contains(edge));*/
                        Color boja = (odabrana.Contains(edge)) ? Colors.Red : Colors.Black;
                        EdgeNaPutu grana = new EdgeNaPutu(cvor, target) { EdgeColor = boja };
                        g.AddEdge(grana);
                        grane.Add(grana);
                    }
                }

                GraphToVisualize = g;
            }
        }

        #endregion

        private void b_brTestova_Click(object sender, RoutedEventArgs e)
        {
            int testovaZaObuhvatPuteva = putanje.Count;
            int testovaZaObuhvatNezavisnihPuteva = putanjeNeovisne.Count;
            int testovaZaObuhvatLinija = ciklomatskakompleksnost;

            MessageBox.Show("Broj testova potrebnih za obuhvat svih puteva je " + testovaZaObuhvatPuteva +"."+Environment.NewLine+
                "Broj testova potrebnih za obuhvat nezavisnih puteva/svih linija je " + testovaZaObuhvatNezavisnihPuteva + "." + Environment.NewLine+
                "V(G) (max. broj nezavisnih puteva)= "+ testovaZaObuhvatLinija + ".");
        }



    }

    public class EdgeNaPutu : TypedEdge<Object>
    {
        public Color EdgeColor { get; set; }

        public EdgeNaPutu(Object source, Object target) : base(source, target, EdgeTypes.General) { }
    }

    public class EdgeColorConverter : IValueConverter
    {

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return new SolidColorBrush((Color)value);
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}
